#include "nfc_hal_dpo.h"
//the value of cw get from p6 3A  p6 3E
/*choose the LPCD_ADC source : EMC  |  Attena
  the array number represent the  distance between card and reader
*/

/*
*cw source from EMC, the difference between EMC and antenna is
*CW value increases in different directions. And CW values from
*EMC has better linearity.
*/

#define ANTENNA 0
#define EMC     1
#define Debug_mode 1

extern uint8_t EMV_DEBUG_LOG;

static uint8_t get_lpcd_adc_data(void)
{
    return hal_nfc_get_register(6,0x3A,1); //use the lpcd_adc values directly
}

static void dpo_set_field_strength(rfalDPOProcess DPOParamSetting)
{
    hal_nfc_set_register(2,0x28,DPOParamSetting.CurrentGsp,1);
}

//static void dpo_recover_field_strength(rfalDPOProcess DPOParamSetting)
//{
//    hal_nfc_set_register(2,0x28,DPOParamSetting.OriginGsp,1);
//}


void rf_get_lpcd_adc_dpo_disable(void)
{
    if(get_rf_status()&&dpo_feature_off()) //use the average of the four real-time lpcd_adc values
    {
        printf("LPCD_ADC:0x%02X\n",hal_nfc_get_register(6,0X3A,1));
    }
}





rfalDPOProcess RFalDPOParam= {

#if ANTENNA
    .ThresholdCW       =0x90,  //maintain the CW at the near threshold
    .StepGsp           =0x02,  //step of adjusting Gsp
    .CurrentGsp        =0x80,  //setting gsp
    .RTuneAdjust       =0x60,  //p7 reg32 rxresistance adjust
    .OriginGsp         =0xF0,  //default Gsp's value ,using in initial phase
    .ThresholdGsp_Max  =0xF0,  //Gsp's max value
    .ThresholdGsp_Min  =0x20,  //Gsp's min value
    .AdjustCnt         =0x80,  //adjust reg initial cnt,don't less than
    .DPO_Method        =rf_dpo_algorithm_antenna,


#endif

#if EMC
    .ThresholdCW       =0xF9,  //maintain the CW at the near threshold
    .StepGsp           =0x02,  //step of adjusting Gsp always a odd num
    .CurrentGsp        =0x80,  //setting gsp
    .RTuneAdjust       =0x60,  //p7 reg32 rxresistance adjust
    .OriginGsp         =0xF0,  //default Gsp's value ,using in initial phase
    .ThresholdGsp_Max  =0xF0,  //Gsp's max value
    .ThresholdGsp_Min  =0x10,  //Gsp's min value
    .AdjustCnt         =0x68,  //adjust reg initial cnt,don't less than
    .DPO_Method        =rf_dpo_algorithm_emc,

#endif



};

uint32_t printcnt=0;

void rf_dpo_switch(bool IsEn)
{
    if(IsEn)
    {
        if(dpo_feature_on())
        {
            printf("DPO Function is ON.%02X \n",get_lpcd_adc_data());
        }
    }
    else
    {
        if(dpo_feature_off())
        {
            printf("DPO Function is OFF.\n");
        }
    }

}


bool get_rf_status(void)
{
    return (hal_nfc_get_register(1,0x14,1)&0x03) == 0x03 ? true:false;
}

bool dpo_feature_on(void)
{
    hal_nfc_set_register(8,0x34,0x68,1);//turn off arc
//    hal_nfc_set_register(7,0x38,0x0E,1);
    hal_nfc_set_register(7,0x32,RFalDPOParam.RTuneAdjust,1); //set the Rtune
    printf("Rtune :%02X \n",hal_nfc_get_register(7,0x32,1));
    hal_nfc_set_register(6,0x33,0x10,1);//choose the page 6 lpcd adcMeas EN
    return (hal_nfc_get_register(6,0x33,1)&0x10) == 0x10 ? true:false;
}

bool dpo_feature_off(void)
{
    hal_nfc_set_register(3,0x37,0x5A,1);//choose the page 6
    hal_nfc_set_register_bit(0x33,0x00);//lpcd adcMeas DisEN
    return (hal_nfc_get_register(6,0x33,1)&0x10) == 0x10 ? false:true;
}



#if EMC
uint8_t rf_dpo_algorithm_emc(void)
{
    uint8_t meas_cw;

    if(get_rf_status())
    {
        meas_cw = get_lpcd_adc_data();
        if(EMV_DEBUG_LOG&&printcnt==1000)
        {
            printf("meas_cw = %02x RF: %02X\n", meas_cw,hal_nfc_get_register(2,0x28,1));
            printcnt=0;
        }
        else
            printcnt++;
#if Debug_mode
        if(meas_cw>RFalDPOParam.ThresholdCW) //too CLOSE
        {

            if(RFalDPOParam.CurrentGsp>RFalDPOParam.ThresholdGsp_Min)
            {
                RFalDPOParam.CurrentGsp-=RFalDPOParam.StepGsp;
                dpo_set_field_strength(RFalDPOParam);


            }


        }
        else if(meas_cw<RFalDPOParam.ThresholdCW) //too FAR
        {

            if(RFalDPOParam.CurrentGsp<RFalDPOParam.ThresholdGsp_Max)
            {
                RFalDPOParam.CurrentGsp+=RFalDPOParam.StepGsp;
                dpo_set_field_strength(RFalDPOParam);

            }

        }
        else
#endif
        {
            return 0;
        }
    }

    return RFalDPOParam.CurrentGsp;

}

#endif


#if ANTENNA
void rf_dpo_algorithm_antenna(void)
{
    uint8_t meas_cw;

    if(get_rf_status())
    {
        meas_cw = get_lpcd_adc_data();
        if(EMV_DEBUG_LOG)
        {
            printf("meas_cw = %02x RF: %02X\n", meas_cw,hal_nfc_get_register(2,0x28,1));
        }
        if(meas_cw>RFalDPOParam.ThresholdCW) //too FAR
        {

            if(RFalDPOParam.CurrentGsp<RFalDPOParam.ThresholdGsp_Max)
            {
                RFalDPOParam.CurrentGsp+=RFalDPOParam.StepGsp;
                dpo_set_field_strength(RFalDPOParam);
                if(EMV_DEBUG_LOG)
                {
                    printf("--curgsp:%02X after set cw: %02X --\n",RFalDPOParam.CurrentGsp,get_lpcd_adc_data());
                }
            }


        }
        else if(meas_cw<RFalDPOParam.ThresholdCW) //too CLOSE
        {

            if(RFalDPOParam.CurrentGsp>RFalDPOParam.ThresholdGsp_Min)
            {
                RFalDPOParam.CurrentGsp-=RFalDPOParam.StepGsp;
                dpo_set_field_strength(RFalDPOParam);
                if(EMV_DEBUG_LOG)
                {
                    printf("--curgsp:%02X after set cw: %02X --\n",RFalDPOParam.CurrentGsp,get_lpcd_adc_data());
                }
            }

        }
        else
        {

        }
    }

}
#endif



uint8_t  optimum_setting_gsp(uint8_t adjuststep)
{
    uint8_t  meas_cw;
    hal_nfc_set_register(8,0x34,0x68,1);
    hal_nfc_set_register(7,0x38,0x0F,1);
    meas_cw = get_lpcd_adc_data();
#if Debug_mode
    while(adjuststep>0)
    {
        meas_cw = get_lpcd_adc_data();
        if(meas_cw>RFalDPOParam.ThresholdCW) //too CLOSE
        {

            if(RFalDPOParam.CurrentGsp>RFalDPOParam.ThresholdGsp_Min)
            {
                RFalDPOParam.CurrentGsp-=RFalDPOParam.StepGsp;
                dpo_set_field_strength(RFalDPOParam);


            }


        }
        else if(meas_cw<RFalDPOParam.ThresholdCW) //too FAR
        {

            if(RFalDPOParam.CurrentGsp<RFalDPOParam.ThresholdGsp_Max)
            {
                RFalDPOParam.CurrentGsp+=RFalDPOParam.StepGsp;
                dpo_set_field_strength(RFalDPOParam);

            }

        }
        else
        {
            break; //get the optimum gsp value
        }
        adjuststep--;
    }
#endif
    printf("RF:%02X cw:%02X lftstep %02X:\n",hal_nfc_get_register(2,0x28,1),meas_cw,adjuststep);
    return RFalDPOParam.CurrentGsp;
}


